using System;

namespace Com.FirstSolver.Splash;

public class FpCurve : ECCurve
{
	private readonly BigInteger q;

	private readonly FpPoint infinity;

	public BigInteger Q => q;

	public override ECPoint Infinity => infinity;

	public override int mFieldSize => q.BitLength;

	public FpCurve(BigInteger q, BigInteger a, BigInteger b)
	{
		this.q = q;
		base.a = FromBigInteger(a);
		base.b = FromBigInteger(b);
		infinity = new FpPoint(this, null, null);
	}

	public override ECFieldElement FromBigInteger(BigInteger x)
	{
		return new FpFieldElement(q, x);
	}

	public override ECPoint CreatePoint(BigInteger X1, BigInteger Y1, bool withCompression)
	{
		return new FpPoint(this, FromBigInteger(X1), FromBigInteger(Y1), withCompression);
	}

	protected internal override ECPoint DecompressPoint(int yTilde, BigInteger X1)
	{
		ECFieldElement x = FromBigInteger(X1);
		ECFieldElement alpha = x.Square().Add(a).Multiply(x)
			.Add(b);
		ECFieldElement beta = alpha.Sqrt();
		if (beta == null)
		{
			throw new ArithmeticException("Invalid point compression");
		}
		BigInteger betaValue = beta.ToBigInteger();
		int bit0 = (betaValue.TestBit(0) ? 1 : 0);
		if (bit0 != yTilde)
		{
			beta = FromBigInteger(q.Subtract(betaValue));
		}
		return new FpPoint(this, x, beta, withCompression: true);
	}

	public override bool Equals(object obj)
	{
		if (obj == this)
		{
			return true;
		}
		if (!(obj is FpCurve other))
		{
			return false;
		}
		return Equals(other);
	}

	protected bool Equals(FpCurve other)
	{
		return Equals((ECCurve)other) && q.Equals(other.q);
	}

	public override int GetHashCode()
	{
		return base.GetHashCode() ^ q.GetHashCode();
	}
}
